//============================================================================
// Name        : NodeCovering.cpp
// Author      : Angelo
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

/*************************************************************************
 * INCLUSIONS
 ************************************************************************/

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <omp.h>

#include "Config.h"
#include "EnvironmentArea.h"
#include "StemIslands.h"
#include "Printer.h"
#include "Statistics.h"
#include "Grafo.h"

#define MAX_THREADS		32

using namespace std;

/*************************************************************************
 * DEFINITIONS
 ************************************************************************/

#define INPUT_PARAMETERS 3

/*************************************************************************
 * FUNCTIONS IMPLEMENTATION
 ************************************************************************/

int main(int argc, char* argv[]) {

	Config *conf;
	EnvironmentArea *ea;
	Printer *printer;
	Statistics *statistics;
	StemIslands *stemIslands[N_ALGO];
	Grafo *initialGraph[N_ALGO];
	Grafo *finalGraph[N_ALGO];
	Grafo *finalStemGraph[N_ALGO];
	int idx_start_algo, idx_end_algo;

	for (int k = 0; k < N_ALGO; k++) {
		stemIslands[k] = NULL;
		initialGraph[k] = NULL;
		finalGraph[k] = NULL;
		finalStemGraph[k] = NULL;
	}

	if (argc != (INPUT_PARAMETERS + 1)){
		cerr << "!!!Wrong parameters!!!" << endl;

		cerr << "USAGE: NodeCovering config_file input_file output_file" << endl;

		return EXIT_FAILURE;
	}

	cout << "Reading configuration from file: " << argv[1] << endl;
	conf = Config::readConfigFromGoodFile(argv[1]);

	if (conf == NULL) {
		cerr << "No configuration file found" << endl;
		cerr << "Searching for \"" << argv[1] << "\"" << endl;
		return EXIT_FAILURE;
	}

	printer = new Printer(argv[3], conf);
	statistics = new Statistics(argv[3], conf);

	cout << "Initializing the environment" << endl;

	ea = new EnvironmentArea(conf->nChannels);
	if (conf->randomArea) {
		ea->initializeRandomly(conf->xMax, conf->yMax, conf->radius, conf->nChannels, conf->lambdaPoisson,
				conf->minNumberCenterGravity, conf->maxNumberCenterGravity,
				conf->minVarianceGaussian, conf->maxVarianceGaussian);

		printer->printOutRamdomMap(ea);
	}
	else {
		ea->initializeFromFile(argv[2], conf->xMax, conf->yMax, conf->radius, conf->nChannels);
	}

	// stampo la mappa dei nodi
	printer->printOutSurvivorsMap(ea);

	cout << "Map created" << endl;

	if (conf->algoToUse == ALL_ALGO) {
		idx_start_algo = 0;
		idx_end_algo = N_ALGO;
	}
	else {
		idx_start_algo = conf->algoToUse;
		idx_end_algo = conf->algoToUse + 1;
	}

	// eseguo l'algoritmo per entrambi i casi: SCR SCD
	for (int algo_idx = idx_start_algo; algo_idx < idx_end_algo; algo_idx++) {
		initialGraph[algo_idx] = new Grafo();

		// calcolo la mappa dei possibili nodi STEM di copertura
		conf->useDiskAlgorithm = algo_idx;
		conf->algoToUse = algo_idx;
		stemIslands[algo_idx] = ea->calculateCoveringNodes(conf);

		// stampo la mappa dei nodi e la mappa dei StemIslands
		printer->printOutStemIslands_GENERIC(stemIslands[algo_idx], ea, algo_idx);

		// prima creo il grafo delle isole
		initialGraph[algo_idx]->createFromStemIslands(stemIslands[algo_idx]);

		// aggiungo gli steiner node 3 a 3
		initialGraph[algo_idx]->add3SteinerPoints();

		// stampo il grafo con gli steiner points
		printer->printOutAllNodeAndSteiner(initialGraph[algo_idx], algo_idx);
		// stampo il grafo con gli steiner points con i collegamenti solo con gli steiner
		printer->printOutAllNodeAndOnlySteiner(initialGraph[algo_idx], algo_idx);

		// Calcolo l'albero MVC
		cout << "Making the MVC tree for algo: " << Config::ALGO_NAME[algo_idx] << endl;
		if (conf->parallelComputation) {
			finalGraph[algo_idx] = initialGraph[algo_idx]->MVCseekerParallel(conf->radiusNet, conf->budget, conf->nThread);
		}
		else {
			finalGraph[algo_idx] = initialGraph[algo_idx]->MVCseeker(conf->radiusNet, conf->budget);
		}

		// stampo l'albero finale
		printer->printOutFinalGraph(finalGraph[algo_idx], algo_idx);

		// inserisco gli stem node nel grafo
		finalStemGraph[algo_idx] = finalGraph[algo_idx]->insertStemNodeOnEdgeFinal(conf->nRadios, conf->radiusNet);

		// stampo l'albero finale c6n gli stem node
		printer->printOutFinalGraphWithStem(finalStemGraph[algo_idx], algo_idx);
	}

	cout << "Printing stats..." << endl;

	// stampo le statistiche finali
	statistics->printFinalStatistics(ea, stemIslands, finalGraph, finalStemGraph);

	cout << "!!!End work!!!" << endl;
	return EXIT_SUCCESS;
}
